home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / updates / update18.zoo / libg++ / src / dtoa.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-22  |  7.1 KB  |  338 lines

  1. /* 
  2. Copyright (C) 1990 Free Software Foundation
  3.     written by Doug Lea (dl@rocky.oswego.edu)
  4.  
  5. This file is part of the GNU C++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17.  
  18. #ifdef __GNUG__
  19. #pragma implementation
  20. #endif
  21. #include <builtin.h>
  22. #include <math.h>
  23. #include <values.h>
  24. #include <xallocri.h>
  25.  
  26. extern AllocRing _libgxx_fmtq;
  27.  
  28. #ifndef M_LN2
  29. #define M_LN2        0.69314718055994530942
  30. #define M_LN10        2.30258509299404568402
  31. #endif
  32.  
  33. char* dtoa(double fpnum,  char cvt, int width, int prec)
  34. {
  35.   // set up workspace
  36.  
  37.   // max possible digits <= those need to show all of prec + exp
  38.   // <= ceil(log10(HUGE)) plus space for null, etc.
  39.  
  40.   const int worksiz = int((M_LN2 / M_LN10) * DMAXEXP) + 8; 
  41.  
  42.   // for fractional part
  43.   char  fwork[worksiz];
  44.   char* fw = fwork;
  45.  
  46.   // for integer part
  47.   char  iwork[worksiz];
  48.   char* iworkend = &iwork[sizeof(iwork) - 1];
  49.   char* iw = iworkend;
  50.   *iw = 0;
  51.  
  52.   // for exponent part
  53.  
  54.   const int eworksiz = int(M_LN2 * _DEXPLEN) + 8;
  55.   char  ework[eworksiz];
  56.   char* eworkend = &ework[sizeof(ework) - 1];
  57.   char* ew = eworkend;
  58.   *ew = 0;
  59.  
  60. #if (_IEEE != 0) && (!defined(atarist))
  61.   if (isinf(fpnum))
  62.   {
  63.     char* inffmt = (char *) _libgxx_fmtq.alloc(5);
  64.     char* inffmtp = inffmt;
  65.     if (fpnum < 0)
  66.       *inffmtp++ = '-';
  67.     strcpy(inffmtp, "Inf");
  68.     return inffmt;
  69.   }
  70.  
  71.   if (isnan(fpnum))
  72.   {
  73.     char* nanfmt = (char *) _libgxx_fmtq.alloc(4);
  74.     strcpy(nanfmt, "NaN");
  75.     return nanfmt;
  76.   }
  77. #endif
  78.  
  79.   // grab sign & make non-negative
  80.   int is_neg = fpnum < 0;
  81.   if (is_neg) fpnum = -fpnum;
  82.  
  83.   // precision matters
  84.  
  85.   if (prec > worksiz - 2) // can't have more prec than supported
  86.     prec = worksiz - 2;
  87.   
  88.   double powprec;
  89.   if (prec == 6)
  90.     powprec = 1.0e6;
  91.   else
  92.     powprec = pow(10.0, (long) prec);
  93.  
  94.   double rounder = 0.5 / powprec;
  95.  
  96.   int f_fmt = cvt == 'f' ||
  97.     ((cvt == 'g') && (fpnum == 0.0 || (fpnum >= 1e-4 && fpnum < powprec)));
  98.  
  99.   int iwidth = 0;
  100.   int fwidth = 0;
  101.   int ewidth = 0;
  102.  
  103.   if (f_fmt)  // fixed format
  104.   {
  105.     double ipart;
  106.     double fpart = modf(fpnum, &ipart);
  107.  
  108.     // convert fractional part
  109.  
  110.     if (fpart >= rounder || cvt != 'g')
  111.     {
  112.       fpart += rounder;
  113.       if (fpart >= 1.0)
  114.       {
  115.         ipart += 1.0;
  116.         fpart -= 1.0;
  117.       }
  118.       double ffpart = fpart;
  119.       double ifpart;
  120.       for (int i = 0; i < prec; ++i)
  121.       {
  122.         ffpart = modf(ffpart * 10.0, &ifpart);
  123.         *fw++ = '0' + int(ifpart);
  124.         ++fwidth;
  125.       }
  126.       if (cvt == 'g')  // inhibit trailing zeroes if g-fmt
  127.       {
  128.         for (char* p = fw - 1; p >= fwork && *p == '0'; --p)
  129.         {
  130.           *p = 0;
  131.           --fwidth;
  132.         }
  133.       }
  134.     }
  135.  
  136.     // convert integer part
  137.     if (ipart == 0.0)
  138.     {
  139.       if (cvt != 'g' || fwidth < prec || fwidth < width)
  140.       {
  141.         *--iw = '0'; ++iwidth;
  142.       }
  143.     }
  144.     else if (ipart <= double(MAXLONG)) // a useful speedup
  145.     {
  146.       long li = long(ipart);
  147.       while (li != 0)
  148.       {
  149.         *--iw = '0' + (li % 10);
  150.         li = li / 10;
  151.         ++iwidth;
  152.       }
  153.     }
  154.     else // the slow way
  155.     {
  156.       while (ipart > 0.5)
  157.       {
  158.         double ff = modf(ipart / 10.0, &ipart);
  159.         ff = (ff + 0.05) * 10.0;
  160.         *--iw = '0' + int(ff);
  161.         ++iwidth;
  162.       }
  163.     }
  164.  
  165.     // g-fmt: kill part of frac if prec/width exceeded
  166.     if (cvt == 'g')
  167.     {
  168.       int m = prec;
  169.       if (m < width)
  170.         m = width;
  171.       int adj = iwidth + fwidth - m;
  172.       if (adj > fwidth)
  173.         adj = fwidth;
  174.       if (adj > 0)
  175.       {
  176.         for (char* f = &fwork[fwidth-1]; f >= fwork && adj > 0; --adj, --f)
  177.         {
  178.           --fwidth;
  179.           char ch = *f;
  180.           *f = 0;
  181.           if (ch > '5') // properly round: unavoidable propagation
  182.           {
  183.             int carry = 1;
  184.             for (char* p = f - 1; p >= fwork && carry; --p)
  185.             {
  186.               ++*p;
  187.               if (*p > '9')
  188.                 *p = '0';
  189.               else
  190.                 carry = 0;
  191.             }
  192.             if (carry)
  193.             {
  194.               for (p = iworkend - 1; p >= iw && carry; --p)
  195.               {
  196.                 ++*p;
  197.                 if (*p > '9')
  198.                   *p = '0';
  199.                 else
  200.                   carry = 0;
  201.               }
  202.               if (carry)
  203.               {
  204.                 *--iw = '1';
  205.                 ++iwidth;
  206.                 --adj;
  207.               }
  208.             }
  209.           }
  210.         }
  211.       }
  212.     }
  213.               
  214.   }
  215.   else  // e-fmt
  216.   {
  217.     
  218.     // normalize
  219.     int exp = 0;
  220.     while (fpnum >= 10.0)
  221.     {
  222.       fpnum *= 0.1;
  223.       ++exp;
  224.     }
  225.     double almost_one = 1.0 - rounder;
  226.     while (fpnum > 0.0 && fpnum < almost_one)
  227.     {
  228.       fpnum *= 10.0;
  229.       --exp;
  230.     }
  231.     
  232.     double ipart;
  233.     double fpart = modf(fpnum, &ipart);
  234.  
  235.  
  236.     if (cvt == 'g')     // used up one digit for int part...
  237.     {
  238.       --prec;
  239.       powprec /= 10.0;
  240.       rounder = 0.5 / powprec;
  241.     }
  242.  
  243.     // convert fractional part -- almost same as above
  244.     if (fpart >= rounder || cvt != 'g')
  245.     {
  246.       fpart += rounder;
  247.       if (fpart >= 1.0)
  248.       {
  249.         fpart -= 1.0;
  250.         ipart += 1.0;
  251.         if (ipart >= 10.0)
  252.         {
  253.           ++exp;
  254.           ipart /= 10.0;
  255.           fpart /= 10.0;
  256.         }
  257.       }
  258.       double ffpart = fpart;
  259.       double ifpart;
  260.       for (int i = 0; i < prec; ++i)
  261.       {
  262.         ffpart = modf(ffpart * 10.0, &ifpart);
  263.         *fw++ = '0' + int(ifpart);
  264.         ++fwidth;
  265.       }
  266.       if (cvt == 'g')  // inhibit trailing zeroes if g-fmt
  267.       {
  268.         for (char* p = fw - 1; p >= fwork && *p == '0'; --p)
  269.         {
  270.           *p = 0;
  271.           --fwidth;
  272.         }
  273.       }
  274.     }
  275.  
  276.     
  277.     // convert exponent
  278.  
  279.     char eneg = exp < 0;
  280.     if (eneg) exp = - exp;
  281.  
  282.     while (exp > 0)
  283.     {
  284.       *--ew = '0' + (exp % 10);
  285.       exp /= 10;
  286.       ++ewidth;
  287.     }
  288.  
  289.     while (ewidth < 2)  // ensure at least 2 zeroes
  290.     {
  291.       *--ew = '0';
  292.       ++ewidth;
  293.     }
  294.  
  295.     *--ew = eneg ? '-' : '+';
  296.     *--ew = 'e';
  297.  
  298.     ewidth += 2;
  299.  
  300.     // convert the one-digit integer part
  301.     *--iw = '0' + int(ipart);
  302.     ++iwidth;
  303.     
  304.   }
  305.  
  306.   // arrange everything in returned string
  307.  
  308.   int showdot = cvt != 'g' || fwidth > 0;
  309.  
  310.   int fmtwidth = is_neg + iwidth + showdot + fwidth + ewidth;
  311.   
  312.   int pad = width - fmtwidth;
  313.   if (pad < 0) pad = 0;
  314.   
  315.   char* fmtbase = (char *) _libgxx_fmtq.alloc(fmtwidth + pad + 1);
  316.   char* fmt = fmtbase;
  317.   
  318.   for (int i = 0; i < pad; ++i) *fmt++ = ' ';
  319.   
  320.   if (is_neg) *fmt++ = '-';
  321.   
  322.   for (i = 0; i < iwidth; ++i) *fmt++ = *iw++;
  323.   
  324.   if (showdot)
  325.   {
  326.     *fmt++ = '.';
  327.     fw = fwork;
  328.     for (i = 0; i < fwidth; ++i) *fmt++ = *fw++;
  329.   }
  330.   
  331.   for (i = 0; i < ewidth; ++i) *fmt++ = *ew++;
  332.   
  333.   *fmt = 0;
  334.   
  335.   return fmtbase;
  336. }
  337.  
  338.